package com.beiji.usercentert.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.beiji.usercentert.commoon.ErrorCode;
import com.beiji.usercentert.exception.BusinessException;
import com.beiji.usercentert.mapper.TeamMapper;
import com.beiji.usercentert.model.domain.Team;
import com.beiji.usercentert.model.domain.User;
import com.beiji.usercentert.model.domain.UserTeam;
import com.beiji.usercentert.model.dto.TeamQuery;
import com.beiji.usercentert.model.enums.TeamStatusEnum;
import com.beiji.usercentert.model.request.TeamJoinRequest;
import com.beiji.usercentert.model.request.TeamQuitRequest;
import com.beiji.usercentert.model.request.TeamUpdateRequest;
import com.beiji.usercentert.model.vo.TeamUserVO;
import com.beiji.usercentert.model.vo.UserVO;
import com.beiji.usercentert.service.TeamService;
import com.beiji.usercentert.service.UserService;
import com.beiji.usercentert.service.UserTeamService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author wangzhi
 * @description 针对表【team(队伍)】的数据库操作Service实现
 * @createDate 2024-07-19 15:15:53
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

    @Resource
    private UserTeamService userTeamService;
    @Resource
    private UserService userService;

    /**
     * 创建队伍
     *
     * @param team      队伍
     * @param loginUser 当前登录用户
     * @return 用户Id
     */
    @Override
    @Transactional
    public Long addTeam(Team team, User loginUser) {
        //判断是否为null
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //判断用户是否登录
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //检验信息
        //队伍人数
        //是否Optional是为了使用它的时候防止空指针异常
        int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不合法");
        }

        //队伍标题
        String name = team.getName();
        if (StringUtils.isBlank(name) || name.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不合法");
        }

        //队伍描述
        String description = team.getDescription();
        if (StringUtils.isNotBlank(description) && description.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述不合法");
        }

        //status 队伍状态
        //校验队伍状态是否合法
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getEnumByValue(status);
        if (teamStatusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不合法");
        }

        //如果是加密状态，必须有密码，并且密码要合法
        String password = team.getPassword();
        if (teamStatusEnum.equals(TeamStatusEnum.SECRET)) {
            if (password == null || password.length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码不合法");
            }
        }

        //超时时间大于当前时间
        Date expireTime = team.getExpireTime();
        if (new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍时间不合法");
        }

        //用户队伍最多创建5个
        Long userId = team.getUserId();
        Long teamNum = lambdaQuery().eq(Team::getUserId, userId).count();
        if (teamNum > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍数量不合法");
        }

        //插入队伍
        team.setId(null);
        //用户id
        team.setUserId(userId);
        boolean result = this.save(team);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }

        //插入 队伍 - 用户
        UserTeam userTeam = new UserTeam();
        userTeam.setTeamId(team.getId());
        userTeam.setUserId(userId);
        userTeam.setJoinTime(new Date());
        result = userTeamService.save(userTeam);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍-用户失败");
        }

        return team.getId();

    }

    /**
     * 查询队伍列表
     *
     * @param teamQuery
     * @param isAdmin
     * @return
     */
    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery, boolean isAdmin) {
        List<Team> teamList = null;
        //非空根据条件查，为空返回一个空
        if (teamQuery != null) {
            //条件
            Long id = teamQuery.getId();
            String name = teamQuery.getName();
            String description = teamQuery.getDescription();
            Integer maxNum = teamQuery.getMaxNum();
            Long userId = teamQuery.getUserId();
            Set<Long> idList = teamQuery.getIdList();
            //判断状态
            //不是管理员，不能查询公开之外的小队
            Integer status = teamQuery.getStatus();
            TeamStatusEnum teamStatusEnum = TeamStatusEnum.getEnumByValue(status);
            if (teamStatusEnum == null) {
                //说明不是0 1 2， 设置为可查询
                //那我后面是根据status查询的，你不是0 1 2让我怎么查? -> 写死写成魔法值?
                //status = TeamStatusEnum.PUBLIC.getValue();

                teamStatusEnum = TeamStatusEnum.PUBLIC;
            }
            if (!isAdmin && !teamStatusEnum.equals(TeamStatusEnum.PUBLIC)) {
                throw new BusinessException(ErrorCode.NOT_AUTH, "没有权限");
            }

            teamList = this.lambdaQuery()
                    .eq(id != null && id > 0, Team::getId, id)  // 队伍主键
                    .in(CollectionUtils.isNotEmpty(idList), Team::getId, idList) // 队伍主键集合
                    .like(StringUtils.isNotBlank(name), Team::getName, name) // 队伍名字
                    .like(StringUtils.isNotBlank(description), Team::getDescription, description) // 队伍描述
                    .eq(maxNum != null && maxNum > 0, Team::getMaxNum, maxNum) // 队伍最大人数
                    .and(qw -> qw.gt(Team::getExpireTime, new Date()).or().isNull(Team::getExpireTime)) // 队伍过期时间
                    .eq(userId != null && userId > 0, Team::getUserId, userId) //队伍创建人id
                    .eq(Team::getStatus, status) // 队伍状态
                    .list();
        }

        //如果为空返回一个空
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }

        //关联创建人信息
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        for (Team team : teamList) {
            Long userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);

            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);

            if (user != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user, userVO);
                teamUserVO.setUserVO(userVO);
            }
            teamUserVOList.add(teamUserVO);

        }

        return teamUserVOList;
    }

    /**
     * 更新队伍信息
     *
     * @param teamUpdateRequest 队伍信息
     * @param loginUser         当前登录用户
     * @return
     */
    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        //判断请求参数是否为空
        if (teamUpdateRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //查询队伍是否存在
        Long id = teamUpdateRequest.getId();
        Team oldTeam = this.getById(id);
        if (oldTeam == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "修改的队伍不存在");
        }

        //只有管理员和创建人才可以修改队伍信息
        if (!userService.isAdmin(loginUser) && !Objects.equals(teamUpdateRequest.getUserId(), loginUser.getId())) {
            throw new BusinessException(ErrorCode.NOT_AUTH, "没有权限");
        }

        //如果更新的状态有加密，则必须要有密码
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(teamUpdateRequest.getStatus());
        if (enumByValue.equals(TeamStatusEnum.SECRET)) {
            if (StringUtils.isBlank(teamUpdateRequest.getPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "加密状态下必要要有密码");
            }
        }

        Team newTeam = new Team();
        BeanUtils.copyProperties(teamUpdateRequest, newTeam);

        //更新用户信息
        return this.updateById(newTeam);
    }

    /**
     * 加入队伍
     *
     * @param teamJoinRequest
     * @param loginUser
     * @return
     */
    @Override
    public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {

        //非空
        if (teamJoinRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //队伍是否存在
        Long teamId = teamJoinRequest.getId();
        Team team = this.lambdaQuery().eq(Team::getId, teamId).one();
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }

        //用户最多加入5个队伍
        Long userId = loginUser.getId();
        Long joinTeamNum = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId).count();
        if (joinTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入5个队伍");
        }

        //不能加入过期队伍
        Date expireTime = team.getExpireTime();
        if (expireTime.before(new Date())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已过期");
        }

        //不能重复加入队伍
        UserTeam joinedTeam = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .eq(UserTeam::getTeamId, teamId)
                .one();
        if (joinedTeam != null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能重复加入");
        }

        Integer status = team.getStatus();
        String password = teamJoinRequest.getPassword();
        TeamStatusEnum enumByValue = TeamStatusEnum.getEnumByValue(status);
        //禁止加入私有队伍
        if (TeamStatusEnum.PRIVATE.equals(enumByValue)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能加入私有队伍");
        }

        //如果队伍是加密状态必须输入密码
        if (TeamStatusEnum.SECRET.equals(enumByValue)) {
            if (StringUtils.isBlank(password) || !team.getPassword().equals(password)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码为空，或者不正确");
            }
        }

        //添加用户-队伍表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeamService.save(userTeam);
        return false;
    }

    /**
     * 退出队伍
     *
     * @param teamQuitRequest
     * @param loginUser
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        //检验参数
        if (teamQuitRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //检验队伍是否存在
        Long teamId = teamQuitRequest.getId();
        Team team = this.getById(teamId);
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }

        //校验用户是否已加入队伍
        Long userId = loginUser.getId();
        UserTeam userTeam = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .eq(UserTeam::getTeamId, teamId)
                .one();
        if (userTeam == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户已不在该队伍");
        }

        //退出队伍
        //如果只有一个人直接解散队伍
        Long teamNum = userTeamService.lambdaQuery().eq(UserTeam::getTeamId, teamId).count();
        if (teamNum == 1) {
            //删除队伍表中信息
            this.removeById(teamId);
        } else {
            //如果是队长就顺位给第二个加入队伍的用户
            if (Objects.equals(loginUser.getId(), team.getUserId())) {
                //只需要在用户_队伍关系表中查前两位用户即可，提升查询效率
                List<UserTeam> userTeamList = userTeamService.lambdaQuery()
                        .eq(UserTeam::getTeamId, teamId)
                        .last("order by asc id limit 2")
                        .list();
                UserTeam newUserTeam = userTeamList.get(1);

                Team updateTeam = new Team();
                updateTeam.setUserId(newUserTeam.getUserId());
                updateTeam.setId(teamId);
                //更改team中的队长
                boolean result = this.updateById(updateTeam);
                if (!result) {
                    throw new BusinessException(ErrorCode.SYSTEM_EXCEPTION, "更改队长失败");
                }
            }
        }

        //退出队伍
        return userTeamService.removeById(userId);
    }

    /**
     * 注销用户
     *
     * @param id        用户id
     * @param loginUser 登录用户
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteTeam(Long id, User loginUser) {

        //判断队伍是否存在
        Team team = this.getById(id);
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }

        //校验该用户是否为队长
        if (!Objects.equals(team.getUserId(), loginUser.getId())) {
            throw new BusinessException(ErrorCode.NOT_AUTH, "无权限");
        }

        //移除所有队伍的关联信息
        LambdaQueryWrapper<UserTeam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserTeam::getTeamId, id);
        userTeamService.remove(queryWrapper);

        //删除队伍

        return this.removeById(id);
    }

    /**
     * 查询创建或加入的队伍
     *
     * @param teamQuery
     * @return
     */
    @Override
    public List<TeamUserVO> listCreateOrJoinTeam(TeamQuery teamQuery) {

        ArrayList<Long> idList = new ArrayList(teamQuery.getIdList());

        //Set<Long> idList = teamQuery.getIdList();

        //检验当前登录用户id
        Long userId = teamQuery.getUserId();
        if (CollectionUtils.isEmpty(idList) && userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户错误");
        }

        //查询队伍
        List<Team> teamList = this.lambdaQuery()
                .eq(userId != null, Team::getUserId, userId)
                .in(idList != null, Team::getId, idList)
                .list();

        //如果为空返回一个空
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }

        //关联创建人信息
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        for (Team team : teamList) {
            userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);

            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);

            if (user != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user, userVO);
                teamUserVO.setUserVO(userVO);
            }
            teamUserVOList.add(teamUserVO);

        }

        return teamUserVOList;
    }
}




